﻿using MetaProperties.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace MetaProperties.Core.Tests
{
    using Framework;


    /// <summary>
    ///This is a test class for IsolatingFilterPipelineTest and is intended
    ///to contain all IsolatingFilterPipelineTest Unit Tests
    ///</summary>
    [TestClass()]
    public class IsolatingFilterPipelineTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for Resume
        ///</summary>
        [TestMethod()]
        public void ResumeTest()
        {
            bool actionExecuted = false;
            Action action = () => 
                {
                    actionExecuted = true;
                };
            IsolatingFilterPipeline p = new IsolatingFilterPipeline(action, null, (o, a, d) => ((Action)d)());
            PrivateObject param0 = new PrivateObject(p);
            IsolatingFilterPipeline_Accessor target = new IsolatingFilterPipeline_Accessor(param0);

            object sender = this;
            EventArgs args = EventArgs.Empty;

            target.Resume(sender, args);

            Assert.IsTrue(actionExecuted);
        }


        private int handledExceptionCount = 0;
        /// <summary>
        ///A test for Execute
        ///</summary>
        [TestMethod()]
        public void ExecuteTest()
        {
            bool action1Executed = false;
            Action action1 = () => 
                {
                    action1Executed = true;
                    throw new Exception();
                };
            bool action2Executed = false;
            Action action2 = () => 
                {
                    action2Executed = true;
                    throw new Exception();
                };
            
            Delegate handlers = Delegate.Combine(action1, action2);

            bool filter1Called = false;
            bool filter2Called = false;
            IList<IEventFilter> filters = new List<IEventFilter> 
            {
                new DummyFilter(() => filter1Called = true),
                new DummyFilter(() => filter2Called = true) 
            };

            object sender = this;
            EventArgs args = EventArgs.Empty;

            Action<object, EventArgs, Delegate> executeAction = (o, e, d) => ((Action)d)();

            IsolatingEventFilter.UnhandledEventHandlerException += this.IsolatingEventFilter_EventHandlerException;
            IsolatingFilterPipeline.Execute(handlers, filters, sender, args, executeAction);
            IsolatingEventFilter.UnhandledEventHandlerException -= this.IsolatingEventFilter_EventHandlerException;

            Assert.IsTrue(action1Executed);
            Assert.IsTrue(action2Executed);
            Assert.IsTrue(filter1Called);
            Assert.IsTrue(filter2Called);
            Assert.AreEqual(2, this.handledExceptionCount);
        }

        void IsolatingEventFilter_EventHandlerException(object sender, Exception e)
        {
            ++handledExceptionCount;
        }

        private class DummyFilter : IEventFilter
        {
            Action action;

            public DummyFilter(Action action)
            {
                this.action = action;
            }

            public void SetMetaPropertyConfiguration(MetaPropertyConfiguration configuration)
            {
            }

            public void PerformFilter(object sender, EventArgs args, IFilterPipeline pipeline)
            {
                this.action();
                pipeline.Resume(sender, args);
            }
        }
    }
}
